(function($f) { $f.extend.app("5f70f2dc-baeb-40f1-a335-ed6e05ee82f4", function(self) {

	"use strict";

	// NOTE: This is same as any other plugin with two exceptions:
	// 1. Extended using app(...) instead of custom(...) method
	// 2. There is no name given, only Id
	// 	  there would always be only one app plugin which will can be accessed with $f.app,
	//    hence a name definition is not required.
	
	// plugin info
	this.info = {
		// title of the plugin
		title: "My Application",
		version: "0.0.1", // major.minor.build
		description: "This is my application."
	};

	// called only when default page and navigation functionality is not used
	// this gives a place to load ui as required
	// params:
	//	callback (function): Optional. It is passed when either a new navigation is
	//						 being performed or page is being reloaded
	//						 This is not passed when navigation is hapenning because of
	//                       hashTag change
	//						 IMPORTANT: It is very important that callback is executed
	//						 when navigation is complete - or else framework load cycle will break
	// returns (void):	
	this.onNavigationASync = function(callback) {
		// NOTE: 
		// If you follow the framework approach of application development
		// you don't need to write any code here.
		//
		// This is just to show case that it is possible - just in case.
		//	
		
		// do whatever you want here to show required UI, manipulate DOM or whatever
		// e.g., here I am making "body" div visible
		$("#body").show();
		
		// NOTE: In case of 'kernel' and 'core' packages of framework navigation engine
		// is not baked in and therefore this call is executed - but in other packages
		// where navigation engine is baked in, this code does not execute - but you
		// still see that body is set to visible, this is because at the time when
		// "#body" element is moved to its right place in startup structure, it is 
		// automatically set to be visible (though can be controlled by setting configuration
		// option fluidOptions.isSupressAutoBodyVisible to true.
		
		// once you are done with your logic of showing UI, you MUST CALL
		// given callback to complete frameowrk loading and firing post
		// navigation events
		// IMPORTANT: If this is not done, framework will not be loaded
		// completely and state of application will be unstable
		if (isFunction(callback)) {
			callback();
		};
	};
	
	// on after navigation is completed and everything is ready 
	// and focus is set on main screen this is last place in 
	// navigation cycle
	// returns (void):
	this.onReadyAll = function() { 
		$("#message").append("<h1>Hello World!</h1> <p> You are using " + $f.info.title + ", Version " + $f.info.version.version + " (" + $f.info.version.name + ") in '" + $f.info.version.package.type + "' package.");
	};

	// on application error
	// this is called if framework catches any unhandled error
	// params: 
	//	message (string): error message
	//	url (string): url of the document in which error is
	//	lineNumber (number): line number of the document where error is
	// returns (boolean):		
	//	true: if no error dialog is required
	//	false: if an error dialog is required
	this.onApplicationError = function(message, url, lineNumber) {
		// handle it here
		alert("This unhandled error is handled by $f.app.onApplicationError() function.");
	
		// return
		return false;
	};	
	
	// on before plugin load
	// this is called before a plugin has just inatantiated but its pre-init is not called
	// params:
	//	plugin (object): plugin object that is being loaded
	// returns (boolean): 
	//	true: if it is ok to let plugin load
	//	false: if plugin load needs to stop
	this.onBeforePluginLoad = function(plugin) { 
		// show
		$("#eventslog").append("<p>" + plugin.handle.name + " is about to load.");
		
		// choice
		var okToLoad = true;
		if (plugin.handle.name === "myPlugin2") {
			okToLoad = $f.confirm("Do you want to load myPlugin2?");
			if (!okToLoad) {
				$("#eventslog").append("<p>" + plugin.handle.name + " load stopped.");
			};
		};
		
		// return 
		return okToLoad;
	};
	
	// on after plugin load
	// this is called after a plugin has completed loading and is also ready
	// params:
	//	plugin (object): plugin object that was loaded
	// returns (void):
	this.onAfterPluginLoad = function(plugin) { 
		// show
		$("#eventslog").append("<p>" + plugin.handle.name + " was just loaded.");
		
		// update list
		$f.myPlugin1.showPluginsList();
	};
	
	// on before feature load
	// this is called before a feature definition is being registered
	// params:
	//	featureDefinition (object): feature definition object that is being registered
	// returns (boolean): 
	//	true: if it is ok to let feature definition to register
	//	false: if feature definition registeration needs to stop
	this.onBeforeFeatureLoad = function(featureDefinition) { 
		// show
		$("#eventslog").append("<p>" + featureDefinition.name + " feature is about to register.");
		
		// return 
		return true;
	};
	
	// on after feature load
	// this is called after a feature definition was registered and feature attach to target
	// plugins was performed (except feature's include processing completion)
	// params:
	//	featureDefinition (object): feature definition object that was just registered
	// returns (void):
	this.onAfterFeatureLoad = function(featureDefinition) { 
		// show
		$("#eventslog").append("<p>" + featureDefinition.name + " feature was just registerd.");
	};
}); }(fluid));